//
//  AppDelegate.m
//  UUCharterSupplier
//
//  Created by ZhangAo on 09/01/2018.
//  Copyright © 2018 UUCharter. All rights reserved.
//

#import "AppDelegate.h"

#ifdef DEBUG
#import <FLEX/FLEX.h>
#endif

#import "UUModuleController.h"
#import <UUFoundation/DKReachabilityManager.h>

#import <UUFoundation/DKDataManager.h>
#import <UUFoundation/UUPersistenceManager.h>
#import <UUFoundation/DKTextField.h>
#import <UUFoundation/DKVerifyCodeCountdownView.h>
#import <UUFoundation/UINavigationBar+RemoveIOS11Margins.h>
#import <UUFoundation/UIBarButtonItem+CustomButton.h>

#import "UUResourceManager.h"
#import "UULoginManager.h"
#import "UUUserManager.h"
#import "UUPushManager.h"
#import <UUFoundation/UURequestModel.h>

#import "UULoginVC.h"
#import "UUAppIntroduceVC.h"
#import "UUTabBarViewController.h"

#import "UUHybridSelectFleetHandler.h"
#import "UUHybridSelectCarHandler.h"
#import "UUHybridSelectDriverHandler.h"
#import "UUHybridSelectPackageHandler.h"
#import "UUHybridSelectLineHandler.h"
#import "UUHybridSelectPeakSeasonHandler.h"
#import "UUHybridOpenSpecEditHandler.h"
#import "UUHybridOpenSpecDetailHandler.h"

@interface AppDelegate () <DKReachabilityManagerObserver>

@property (nonatomic, strong) UUModuleController *moduleController;
@property (nonatomic, strong) UUPushManager *pushManager;
@property (nonatomic, assign) BOOL enterLogin;

@property (nonatomic, weak, readwrite) UITabBarController *tabBarController;

@end

@implementation AppDelegate

void uncaughtExceptionHandler(NSException *exception) {
    DKLog(@"CRASH: %@", exception);
    DKLog(@"Stack Trace: %@", [exception callStackSymbols]);
}

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSSetUncaughtExceptionHandler(&uncaughtExceptionHandler);
    
    DKLog(@"Document Path:\n%@", pathInDoc(@""));
    DKLog(@"Bundle Path:\n%@", [NSBundle mainBundle].bundlePath);
    DKLog(@"Temp Path:\n%@", pathInTmp(nil));
    
    // 初始化通知服务
    self.pushManager = [[UUPushManager alloc] initWithLaunchOptions:launchOptions];
    
    if (@available(iOS 11.0, *)) {
        [UINavigationBar removeMargins];
    }
    
    // 为了防止5.5寸机型从横屏启动时, StatusBar依然横屏
    application.statusBarOrientation = UIInterfaceOrientationPortrait;
    
    application.statusBarStyle = UIStatusBarStyleLightContent;
    
    [[UINavigationBar appearance] setBackIndicatorImage:GetResourceManager().navigationBarBackImage];
    [[UINavigationBar appearance] setBarTintColor:COMMON_NAVIGATIONBAR_COLOR];
    [[UINavigationBar appearance] setTintColor:[UIColor whiteColor]];
    [[UINavigationBar appearance] setBarStyle:UIBarStyleDefault];
    [[UINavigationBar appearance] setTitleTextAttributes:@{
                                                           NSForegroundColorAttributeName : [UIColor whiteColor]
                                                           }];
    
    [[DKTextField appearance] setBottomLineColor:COMMON_SEPARATOR_COLOR];
    
    [UIBarButtonItem setCommonButtonTitleHighlightColor:[UIColor lightGrayColor]];
    [UIBarButtonItem setCommonFontName:GetResourceManager().iconFontName];
    
    [[DKVerifyCodeCountdownView appearance] setNormalColor:[UIColor blueColor]];
    [[DKVerifyCodeCountdownView appearance] setDisabledColor:[UIColor grayColor]];
    
    [DKModel setGlobalDateToObjectBlock:^id(NSDate *date, DKModel *model) {
        return @([date timeIntervalSince1970]);
    }];
    
    [DKModel setGlobalObjectToDateBlock:^NSDate *(id object, DKModel *model) {
        return [NSDate dateWithTimeIntervalSince1970:[object longLongValue]];
    }];
    
    [UUPersistenceManager setUserIdRequestBlock:^id {
        return GetCurrentUser().userId;
    }];
    
    [UURequestModel setHeadersBlock:^NSDictionary *{
        if ([GetLoginManager() isLogin]) {
            return @{
                     @"version_code" : @"1",
                     @"platform" : @"2",
                     @"did" : GetDeviceInfo().uuid,
                     @"Authorization" : GetLoginManager().currentUser.token
                     };
        } else {
            return @{
                     @"version_code" : @"1",
                     @"platform" : @"2",
                     @"did" : GetDeviceInfo().uuid,
                     };
        }
    }];
    
    NSMutableArray<Class> *handlers = [NSMutableArray new];
    [handlers addObject:[UUHybridSelectFleetHandler class]];
    [handlers addObject:[UUHybridSelectCarHandler class]];
    [handlers addObject:[UUHybridSelectDriverHandler class]];
    [handlers addObject:[UUHybridSelectPackageHandler class]];
    [handlers addObject:[UUHybridSelectLineHandler class]];
    [handlers addObject:[UUHybridSelectPeakSeasonHandler class]];
    [handlers addObject:[UUHybridOpenSpecEditHandler class]];
    [handlers addObject:[UUHybridOpenSpecDetailHandler class]];
    
    [UUHybridWebVC registerCommonHandlers:handlers];
    
#ifdef HTTP_CONNECTION_LOG
    [DKDataManager enableConnectionLog:YES];
#endif
    
    [DKDataManager setHookToHandlingGlobalError:^BOOL(NSError *__autoreleasing *error) {
        NSInteger errorCode = (*error).code;
        if (errorCode == NSURLErrorTimedOut) {
            *error = [NSError makeErrorWithCode:errorCode message:@"网络超时，请稍后再试"];
        } else if (errorCode == NSURLErrorNotConnectedToInternet) {
            *error = [NSError makeErrorWithCode:errorCode message:@"网络连接失败，请检查网络"];
        } else if (errorCode == 401) {
            POST_MSG_WITH_OBJ_DICT(NOTIFICATION_USER_NEED_LOGOUT, @"用户验证过期，请重新登录", @{LOGOUT_REASON_KEY:@(UULogoutReasonTypeTokenInvalid)});
            return YES;
        }
        
        return NO;
    }];
    
    [GetReachabilityManager() addObserver:self];
    
    BIND_MSG(NOTIFICATION_USER_NEED_LOGOUT, @selector(logout:));

    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.backgroundColor = [UIColor whiteColor];
    
    UIViewController *destinationVC;
    
    if (GetLoginManager().isLogin) {
        destinationVC = [self createTabBarVC];
        self.tabBarController = (UITabBarController *)destinationVC;
    } else {
        destinationVC = [self createLoginVC];
    }
    
    WEAK_SELF();
    UUAppIntroduceVC *appIntroduceVC = [UUAppIntroduceVC initWithCompleteBlock:^{
        [[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationNone];
        
        if (weakSelf.enterLogin) {
            weakSelf.enterLogin = NO;
            weakSelf.tabBarController = nil;
            [weakSelf changeRootViewController:[weakSelf createLoginVC] completeBlock:nil];
        } else {
            [weakSelf changeRootViewController:destinationVC completeBlock:nil];
        }
    }];
    
    self.window.rootViewController = appIntroduceVC;
    [self.window makeKeyAndVisible];
    
#ifdef DEBUG
    UITapGestureRecognizer *gesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(showFLEX)];
    gesture.numberOfTapsRequired = 2;
    gesture.numberOfTouchesRequired = 2;
    [self.window addGestureRecognizer:gesture];
#endif
    
    self.moduleController = [UUModuleController new];
    [self.moduleController setupWithLaunchOptions:launchOptions];
    
    if (GetLoginManager().isLogin) {
        [self loginSetup];
    }
    
    return YES;
}

- (void)applicationWillResignActive:(UIApplication *)application {
    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
    // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}

- (void)applicationDidEnterBackground:(UIApplication *)application {
    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}

- (void)applicationWillEnterForeground:(UIApplication *)application {
    // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
    
    [self.moduleController awakeFromBackground];
    
    [[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}

- (void)applicationDidBecomeActive:(UIApplication *)application {
    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}

- (void)applicationWillTerminate:(UIApplication *)application {
    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}

#pragma mark - Push

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
    if (GetLoginManager().isLogin) {
        [self.pushManager registerDeviceWithToken:deviceToken];
    }
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
    [self.pushManager didReceiveRemoteNotification:userInfo];
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
    [self.pushManager didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
}

#pragma mark - FLEX

#ifdef DEBUG
- (void)showFLEX {
    [[FLEXManager sharedManager] showExplorer];
}
#endif

#pragma mark - Private methods

- (void)loginSetup {
    [self.moduleController userDidLogin];
    
    [self.pushManager registerPush];
}

- (void)logout:(NSNotification *)notification {
    self.tabBarController = nil;
    
    if (GetLoginManager().isLogin) {
        [self.moduleController userDidLogout];
        
        // 注销通知
        [self.pushManager unregisterNotifications];
        
        HideIndicatorInKeyWindow();
        
        UULogoutReasonType reason = [[notification.userInfo valueForKey:LOGOUT_REASON_KEY] integerValue];
        switch (reason) {
            case UULogoutReasonTypeNone:
                [self presentLogin];
                break;
            case UULogoutReasonTypeForceLogout:
            case UULogoutReasonTypeTokenInvalid: {
                NSString *title = notification.object;
                if ([NSString isBlank:title]) {
                    title = reason == UULogoutReasonTypeTokenInvalid
                    ? @"当前账号在其它的移动设备上登录，如非本人操作，请注意账号信息安全！"
                    : @"您的管理权限已发生变化，请重新登录";
                }
                
                UIAlertAction *alertAction = [UIAlertAction actionWithTitle:@"重新登录"
                                                                      style:UIAlertActionStyleDefault
                                                                    handler:^(UIAlertAction *action) {
                                                                        if ([self.window.rootViewController isKindOfClass:[UUAppIntroduceVC class]]) {
                                                                            self.enterLogin = YES;
                                                                        } else {
                                                                            [self presentLogin];
                                                                        }
                                                                    }];
                [UIAlertController presentAlertControllerWithTitle:title actions:@[alertAction]];
            }
                break;
            default:
                [self presentLogin];
                break;
        }
    }
}

- (UIViewController *)createLoginVC {
    UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:[UULoginVC new]];
    return nav;
}

- (UITabBarController *)createTabBarVC {
    UUTabBarViewController *tabBarController = [UUTabBarViewController new];
    return tabBarController;
}

- (void)presentHome {
    WEAK_SELF();
    ShowIndicatorInKeyWindow();
    [GetUserManager() setNeedsUpdateUserInfo];
    [GetUserManager() asyncFetchUserInfoWithCompleteBlock:^(UUUserInfo * _Nullable userInfo, NSError * _Nullable error) {
        HideIndicatorInKeyWindow();
        
        UITabBarController *rootViewController = [weakSelf createTabBarVC];
        weakSelf.tabBarController = rootViewController;
        [weakSelf changeRootViewController:rootViewController completeBlock:nil];
        [weakSelf loginSetup];
    }];
}

- (void)presentLogin {
    UIViewController *rootViewController = [self createLoginVC];
    [self changeRootViewController:rootViewController completeBlock:nil];
}

- (void)changeRootViewController:(UIViewController *)newRootViewController completeBlock:(void (^)(void))completeBlock {
    if (self.window.rootViewController == nil) {
        self.window.rootViewController = newRootViewController;
        return;
    }
    
    UIView *snapshot = [self.window snapshotViewAfterScreenUpdates:NO];
    
    UIViewController *oldViewController = self.window.rootViewController;
    self.window.rootViewController = newRootViewController;
    
    if (oldViewController.presentedViewController) {
        if ([oldViewController isKindOfClass:[UITabBarController class]]) {
            UITabBarController *oldRootVC = (UITabBarController *)oldViewController;
            UIViewController *currentVC = [oldRootVC.viewControllers objectAtIndex:oldRootVC.selectedIndex];
            if ([currentVC isKindOfClass:[UINavigationController class]]) {
                [(UINavigationController *)currentVC setViewControllers:@[]];
            }
        }
        [oldViewController dismissViewControllerAnimated:NO completion:^{
            [oldViewController.view removeFromSuperview];
        }];
    }
    
    [newRootViewController.view addSubview:snapshot];
    [UIView animateWithDuration:0.4 animations:^{
        snapshot.alpha = 0.0;
    } completion:^(BOOL finished) {
        [snapshot removeFromSuperview];
        BLOCK_SAFE_CALLS(completeBlock);
    }];
}

- (void)receiveMessage:(NSDictionary *)message {
    [self.moduleController receiveMessage:message];
}

#pragma mark DKReachabilityManagerObserver methods

- (void)reachabilityNetworkStatusChanged {
    [self.moduleController reachabilityNetworkStatusChanged:GetReachabilityManager().isReachable
                                         isSlowlyNetworking:GetReachabilityManager().isSlowlyNetworking];
}

@end
